#include "TimerWheel.h"
#include "Logger.h"
#include "Channel.h"
#include "TimerTask.h"
#include "EventLoop.h"

#include <sys/timerfd.h>
#include <unistd.h>

int TimerWheel::creatTimerfd()
{
    int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
    if (timerfd < 0)
    {
        LOG_FATAL("TimerWheel::creatTimerfd error: %d: %s", errno, strerror(errno));
    }
    struct itimerspec itime;
    itime.it_value.tv_sec = 1;
    itime.it_value.tv_nsec = 0;
    itime.it_interval.tv_sec = 1;
    itime.it_interval.tv_nsec = 0;
    timerfd_settime(timerfd, 0, &itime, nullptr);
    return timerfd;
}

TimerWheel::TimerWheel(EventLoop *loop)
    : loop_(loop), timerfd_(creatTimerfd()), tick_(0), capacity_(60), wheel_(capacity_), timerChannel_(new Channel(loop, timerfd_))
{
    timerChannel_->setReadCallback(std::bind(&TimerWheel::onTime, this));
    timerChannel_->enableReading();
}

TimerWheel::~TimerWheel()
{
}

// 添加定时任务
void TimerWheel::timerAdd(std::string name, uint32_t timeout, const TaskFunc &cb)
{
    loop_->runInLoop(std::bind(&TimerWheel::timerAddInLoop,this,name,timeout,cb));
}
// 刷新或延迟定时任务
void TimerWheel::timerRefresh(std::string name)
{
    loop_->runInLoop(std::bind(&TimerWheel::timerRefreshInLoop,this,name));
}
// 取消定时任务
void TimerWheel::timerCancel(std::string name)
{
    loop_->runInLoop(std::bind(&TimerWheel::timerCancelInLoop,this,name));
}

// 判断TcpConnection对应的定时任务是否已经存在
bool TimerWheel::hasTimer(std::string name)
{
    auto it = timers_.find(name);
    if (it == timers_.end())
        return false;

    return true;
}

void TimerWheel::removeTimer(std::string name)
{
    auto it = timers_.find(name);
    if (it != timers_.end())
        timers_.erase(it);
}

int TimerWheel::readTimerfd()
{
    /**
     * 超时次数
     * 有可能在处理其他fd的事件时花费了很长时间，到timerfd的事件时已经超时很多次了
     * read从timerfd中读到的就是上一次read后的超时次数
     */
    uint64_t times;
    int ret = read(timerfd_, &times, 8);
    if (ret < 0)
    {
        LOG_FATAL("TimerWheel::readTimerfd error: %d: %s", errno, strerror(errno));
    }
    return times;
}

// 这个函数每秒钟被执行一次，相当于秒针向后走了一步
void TimerWheel::runTimerTask()
{
    tick_ = (tick_ + 1) % capacity_;
    // 清空指定位置的数组，把这个位置挂的所有的shared_ptr<TimerTask>全释放
    wheel_[tick_].clear();
}

void TimerWheel::onTime()
{
    int times = readTimerfd();
    for (int i = 0; i < times; i++)
    {
        runTimerTask();
    }
}

void TimerWheel::timerAddInLoop(std::string name, uint32_t timeout, const TaskFunc &cb)
{
    //new一个定时器任务，用shared_ptr管理生命周期
    ptrTask pt(new TimerTask(name, timeout, cb));
    //设置定时器任务的释放函数，任务被释放，则执行TimerTask::~TimerTask(), 进而执行在其析构函数内的cb
    pt->setRelease(std::bind(&TimerWheel::removeTimer, this, name));
    //计算该任务在时间轮中的位置
    int pos = (tick_ + timeout) % capacity_;
    //插入定时器任务到对应位置
    wheel_[pos].push_back(pt);
    //建立映射关系
    timers_[name] = weakTask(pt);
}

// 刷新定时时间
void TimerWheel::timerRefreshInLoop(std::string name)
{
    auto it=timers_.find(name);
    if(it==timers_.end())
        return; //没找到，无法刷新

    ptrTask pt =it->second.lock();  //这时，又用一个shared_ptr指向TimerTask对象，计数器+1，之前位置的释放，并不会执行析构函数
    int delay = pt->delayTime();
    int pos = (tick_+delay) % capacity_;  
    wheel_[pos].push_back(pt);  //重新插入
}

void TimerWheel::timerCancelInLoop(std::string name)
{
    auto it=timers_.find(name);
    if(it==timers_.end())
        return;

    ptrTask pt =it->second.lock();
    if(pt)
        pt->cancel();
}